﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Data;
using CAION2.Classes;
using CAION2.Commands;
using CAION2.Models;
using CAION2.Properties;

namespace CAION2.ViewModels
{
    class SelectItemDialogViewModel : ViewModelBase
    {
        #region Vars

        private string _tableName = "";
        private ItemPlaceViewModel.EquipmentSlots _slot;
        private BindingListCollectionView _items;
        private DataTable _itemsCollection;
        private DataRowView _selectedItem;
        
        private ObservableCollection<string> _itemParameters;
        private string _selectedParameter;
        private string _parameterField;
        private readonly Dictionary<string, string> _parametersFields;
        private ObservableCollection<bool> _qualityFilter;
        
        private Thickness _filterErrorBorder;
        private string _filterText;

        private ItemCardViewModel _card;

        public string GameClass;
        public byte CharacterLevel;

        #endregion
        
        #region Properties
        
        public ItemPlaceViewModel.EquipmentSlots Slot
        {
            private get { return _slot; }
            set
            {
                if (Equals(_slot, value)) return;
                _slot = value;

                OnPropertyChanged("Slot");
                
                FillItemParameters();
            }
        }

        public BindingListCollectionView Items
        {
            get { return _items; }
            private set
            {
                if (Equals(_items, value)) return;
                _items = value;

                OnPropertyChanged("Items");
            }
        }

        private DataTable ItemsCollection
        {
            get { return _itemsCollection; }

            set
            {
                if (_itemsCollection == value) return;

                _itemsCollection = value;
                OnPropertyChanged("ItemsCollection");
            }
        }

        public string FilterText
        {
            get { return _filterText; }
            set
            {
                if (_filterText == value) return;

                _filterText = value;
                OnPropertyChanged("FilterText");

                ApplyFilter();
            }
        }

        public Thickness FilterErrorBorder
        {
            get { return _filterErrorBorder; }
            private set
            {
                if (_filterErrorBorder == value) return;

                _filterErrorBorder = value;
                OnPropertyChanged("FilterErrorBorder");
            }
        }

        public ObservableCollection<string> ItemParameters
        {
            get { return _itemParameters; }
            private set
            {
                if (Equals(_itemParameters, value)) return;
                _itemParameters = value;

                OnPropertyChanged("ItemParameters");
            }
        }

        public string SelectedParameter
        {
            get { return _selectedParameter; }
            set
            {
                if (Equals(_selectedParameter, value)) return;
                _selectedParameter = value;

                OnPropertyChanged("SelectedParameter");

                ShowSelectedParameter();
            }
        }

        public ObservableCollection<bool> QualityFilter
        {
            get { return _qualityFilter; }
            set
            {
                if (Equals(_qualityFilter, value)) return;
                _qualityFilter = value;

                OnPropertyChanged("QualityFilter");
            }
        }

        public DataRowView SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (Equals(_selectedItem, value)) return;
                _selectedItem = value;

                OnPropertyChanged("SelectedItem");

                ShowCard();
            }
        }
        
        public ItemCardViewModel Card
        {
            get { return _card; }
            private set
            {
                if (Equals(_card, value)) return;
                _card = value;

                OnPropertyChanged("Card");
            }
        }
        
        public String[] MasterItem { private get; set; }

        #endregion

        #region Commands

        public RelayCommand LoadItemsCommand { get; private set; }

        #endregion

        
        public SelectItemDialogViewModel()
        {
            Card = new ItemCardViewModel();

            LoadItemsCommand = new RelayCommand(LoadItems) { IsEnabled = true };

            _parametersFields = new Dictionary<string, string>
                {
                    {Resources._StatsPhyAttack, " CAST(max_damage AS nchar) + ' (' + CAST(min_damage AS nchar) + '-' + CAST(max_damage AS nchar) + ')'"},
                    {Resources._StatsMagicalSkillBoost, "magical_skill_boost"},
                    {Resources._StatsAttackDelay, "CAST((attack_delay/1000.0) AS numeric(4,1))"},
                    {Resources._StatsCritical, "critical"},
                    {Resources._StatsAccuracy, "hit_accuracy"},
                    {Resources._StatsParry, "parry"},
                    {Resources._StatsMagicalHitAccuracy, "magical_hit_accuracy"},
                    {Resources._StatsBlock, "block"},
                    {Resources._StatsDamageReduce, "damage_reduce"},
                    {Resources.Status_LevelColumn, "level"},
                    {Resources._StatsPhysicalDefend, "physical_defend"},
                    {Resources._StatsMagicalResist, "magical_resist"},
                    {Resources._StatsMagicalSkillBoostResist, "magical_skill_boost_resist"},
                    {Resources._StatsDodge, "dodge"},
                };
            
            QualityFilter = ClassConfiguration.GetBoolGroup("SelectItemQualityFilter");
        }

        private void FillItemParameters()
        {
            ItemParameters = new ObservableCollection<string>();

            switch (Slot)
            {
                case ItemPlaceViewModel.EquipmentSlots.Main:
                case ItemPlaceViewModel.EquipmentSlots.Armsfused:
                    ItemParameters.Add(Resources._StatsPhyAttack);
                    ItemParameters.Add(Resources._StatsMagicalSkillBoost);
                    ItemParameters.Add(Resources._StatsAttackDelay);
                    ItemParameters.Add(Resources._StatsCritical);
                    ItemParameters.Add(Resources._StatsAccuracy);
                    ItemParameters.Add(Resources._StatsParry);
                    ItemParameters.Add(Resources._StatsMagicalHitAccuracy);
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Sub:
                case ItemPlaceViewModel.EquipmentSlots.Waist:
                    ItemParameters.Add(Resources._StatsPhyAttack);
                    ItemParameters.Add(Resources._StatsMagicalSkillBoost);
                    ItemParameters.Add(Resources._StatsAttackDelay);
                    ItemParameters.Add(Resources._StatsCritical);
                    ItemParameters.Add(Resources._StatsAccuracy);
                    ItemParameters.Add(Resources._StatsParry);
                    ItemParameters.Add(Resources._StatsMagicalHitAccuracy);
                    ItemParameters.Add(Resources._StatsBlock);
                    ItemParameters.Add(Resources._StatsDamageReduce);
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Wing:
                    ItemParameters.Add(Resources.Status_LevelColumn);
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Head:
                    ItemParameters.Add(Resources._StatsPhysicalDefend);
                    ItemParameters.Add(Resources._StatsMagicalResist);
                    ItemParameters.Add(Resources._StatsMagicalSkillBoostResist);
                    ItemParameters.Add(Resources._StatsDodge);
                    break;

                case ItemPlaceViewModel.EquipmentSlots.RightOrLeftEar:
                case ItemPlaceViewModel.EquipmentSlots.Neck:
                case ItemPlaceViewModel.EquipmentSlots.RightOrLeftFinger:
                    ItemParameters.Add(Resources._StatsMagicalResist);
                    ItemParameters.Add(Resources._StatsMagicalSkillBoostResist);
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Torso:
                case ItemPlaceViewModel.EquipmentSlots.Leg:
                case ItemPlaceViewModel.EquipmentSlots.Foot:
                case ItemPlaceViewModel.EquipmentSlots.Shoulder:
                case ItemPlaceViewModel.EquipmentSlots.Glove:
                    ItemParameters.Add(Resources._StatsPhysicalDefend);
                    ItemParameters.Add(Resources._StatsMagicalResist);
                    ItemParameters.Add(Resources._StatsMagicalSkillBoostResist);
                    ItemParameters.Add(Resources._StatsDodge);
                    break;
            }
        }

        private void LoadItems()
        {
            _tableName = DataModel.GetTableNameFromSlot(Slot);
            
            string fields = "name, translate" + DataModel.EngFix + " AS translate, quality, level";
            if (!string.IsNullOrEmpty(_parameterField)) fields += ", " + _parameterField + " AS parameter";

            string conditions = "";
            List<string> qualities = new List<string> {"common", "rare", "legend", "unique", "epic", "mythic"};
            for (int i = 0; i < 6; i++)
            {
                if (QualityFilter[i]) conditions += "'" + qualities[i] + "',";
            }
            if (!string.IsNullOrEmpty(conditions)) conditions = "quality IN (" + conditions.Remove(conditions.Length - 1) + ")";

            if (CharacterLevel == 0) CharacterLevel = ClassConfiguration.CharacterMaximumLevel;
            if (CharacterLevel < ClassConfiguration.CharacterMaximumLevel)
            {
                if (!string.IsNullOrEmpty(conditions)) conditions += " AND ";
                conditions += "(level <= " + CharacterLevel + ")";
            }

            string classCondition = ClassGameClass.GetGameClassConditionForPlace(GameClass, Slot, MasterItem);
            if (!string.IsNullOrEmpty(classCondition))
            {
                if (!string.IsNullOrEmpty(conditions))
                {
                    conditions += " AND (" + classCondition + ")";
                }
                else
                {
                    conditions = classCondition;
                }
            }
            
            ItemsCollection = DataModel.GetTable(_tableName, fields, conditions);
            Items = (BindingListCollectionView)CollectionViewSource.GetDefaultView(ItemsCollection);

            ApplyFilter();
            SetFilter();
        }
        
        private void ApplyFilter()
        {
            FilterText = CleanInput(FilterText);
            Items.CustomFilter = "translate LIKE '%" + FilterText + "%'";
        }

        static string CleanInput(string strIn)
        {
            if (string.IsNullOrEmpty(strIn)) return strIn;

            try
            {
                return Regex.Replace(strIn, @"[^\w\-\s]", "",
                                     RegexOptions.None, TimeSpan.FromSeconds(0.5));
            }
            
            catch (RegexMatchTimeoutException)
            {
                return String.Empty;
            }
        }

        private void SetFilter()
        {
            if (FilterText != null)
            {
                FilterErrorBorder = Items.Count == 0 ? new Thickness(1) : new Thickness(0);
            }
        }
        
        private void ShowSelectedParameter()
        {
            _parameterField = _parametersFields[SelectedParameter];
            LoadItems();
        }

        private void ShowCard()
        {
            if (_selectedItem == null)
            {
                Card = new ItemCardViewModel {CardVisible = Visibility.Collapsed};
                return;
            }

            DataRow row = DataModel.GetRowAtName(_tableName, _selectedItem["name"].ToString());
            
            if (Slot == ItemPlaceViewModel.EquipmentSlots.Sub) Card.PlaceIndex = 2;
            Card.LoadItem(row);
            Card.LoadCard();
        }
    }
}
